#include <pthread.h>
#include "erl_interface.h"
#include "ei.h"
#include "common.h"
#include "erl3.h"
#include <string>
#include <cstring>
#include "zookeper.h"
/*
class ErlException { };
class ErlConnectInitException : public ErlException { };
class ErlConnectException : public ErlException { };
class ErlDisconnectException : public ErlException { };
*/
using namespace std;

int myerl_init(Myerl *myerl, string cookie, string name, string host)
{
	char* cook = new char[cookie.size()+1];
	string fullname = name.append(host);
	char* hosting = new char[fullname.size()+1];
	int ret = 0;
	int fd;
	strcpy(cook,cookie.c_str());
	strcpy(hosting,fullname.c_str());
	erl_init(NULL, 0);
	if (erl_connect_init(1, cook, 0) == -1)
	{
    ret = -1; //throw ErlConnectInitException();
	}
	else
	{
	  fd = erl_connect(hosting);
	  if (fd < 0)
	  {
      ret = -1; //throw ErlConnectException();
	  }
	  else
	  {
	    myerl->fd = fd;
    }
	}
	/*if (host) // far connection
	{
		struct in_addr address;
		//inet_aton(host, &address); // PROBLEMATIC
		fd = erl_xconnect(&address, name);
	}
	*/

  delete cook;
  delete hosting;
  return ret;
}

void *myerl_listener(void *arg)
{
	Myerl *myerl = (Myerl *) arg;
	unsigned char buffer[100];
	while (myerl->alive)
	{
		ErlMessage erlMsg;
		int erlAns = erl_receive_msg(myerl->fd, buffer, 100, &erlMsg);
		if (erlAns == ERL_ERROR)
		{
			return NULL; //throw ErlDisconnectException();
		}
		else if (erlAns == ERL_TICK)
		{
			// IGNORE
		}
		else if (erlMsg.type == ERL_REG_SEND)
		{
			ETERM *msgType = erl_element(1, erlMsg.msg);
			switch (ERL_INT_VALUE(msgType))
			{
				/*case 0: // i want to contact with you (sorry, maaan, but i won't contact with someone, who use c-like comments)
				{
					myerl->someone_there = erl_element(2, erlMsg.msg);
			    erl_send(myerl->fd, myerl->someone_there, myerl->someone_there);
					printf("dostałem pid\n"); // high-level debugging?;)
				}
				break;*/

				case 1: /* dude, gotta my weed?! */
				{
					ETERM *list = erl_element(2, erlMsg.msg);
					for (int i = erl_length(list); i > 0; --i)
					{
						ETERM *head = erl_hd(list);
						ETERM *tail = erl_tl(list);
						erl_free_term(list);
						list = tail;
						ETERM *varX = erl_element(1, head);
						ETERM *varY = erl_element(2, head);
						ETERM *varVeg = erl_element(3, head);
						erl_free_term(head);
						myerl->common->meadow->setField(ERL_INT_VALUE(varX), ERL_INT_VALUE(varY), ERL_INT_VALUE(varVeg));
                                                //printf("(%d, %d) veg: %f\n",ERL_INT_VALUE(varX), ERL_INT_VALUE(varY), ERL_INT_VALUE(varVeg));
						// myerl->common->meadow->setField(ERL_INT_VALUE(X), ERL_INT_VALUE(Y), ERL_FLOAT_VALUE(Veg));
						// or sedning directly to Qt hex, hm?
						// sth like: myerl->hexMapInterface->setField(ERL_INT_VALUE(X), ERL_INT_VALUE(Y), ERL_FLOAT_VALUE(Veg));
						// HexMapInterface class should care about concurency problems then :P
						erl_free_term(varX);
						erl_free_term(varY);
						erl_free_term(varVeg);
					}
					erl_free_term(list);
					/*
					ETERM *N = erl_element(2, erlMsg.msg);
					for (int i = ERL_INT_VALUE(N), tuple_field = 3; i > 0; --i)
					{
						ETERM *X = erl_element(tuple_field++, erlMsg.msg);
						ETERM *Y = erl_element(tuple_field++, erlMsg.msg);
						ETERM *Veg = erl_element(tuple_field++, erlMsg.msg);
						//printf("(%d, %d) %lf\n", ERL_INT_VALUE(X), ERL_INT_VALUE(Y), ERL_FLOAT_VALUE(Veg)); again high-level debugging?
						myerl->common->meadow->setField(ERL_INT_VALUE(X), ERL_INT_VALUE(Y), ERL_FLOAT_VALUE(Veg));
						// or sedning directly to Qt hex, hm?
						// sth like: myerl->hexMapInterface->setField(ERL_INT_VALUE(X), ERL_INT_VALUE(Y), ERL_FLOAT_VALUE(Veg));
						// HexMapInterface class should care about concurency problems then :P
						erl_free_term(X);
						erl_free_term(Y);
						erl_free_term(Veg);
					}
					erl_free_term(N);
					*/
				}
				break;

				case 2: // {2, Id} -> die animal
				{
					ETERM *varId = erl_element(2, erlMsg.msg);
					myerl->zooKeeper->goodbye(ERL_INT_VALUE(varId));
					erl_free_term(varId);
				}
				break;

				case 3: // {3, Type, Id, X, Y, SW, MW, W, Speed} -> new animal
				{
					ETERM *varType = erl_element(2, erlMsg.msg);
					ETERM *varId = erl_element(3, erlMsg.msg);
					ETERM *varX = erl_element(4, erlMsg.msg);
					ETERM *varY = erl_element(5, erlMsg.msg);
					ETERM *varSW = erl_element(6, erlMsg.msg);
					ETERM *varMW = erl_element(7, erlMsg.msg);
					ETERM *varW = erl_element(8, erlMsg.msg);
					ETERM *varSpeed = erl_element(9, erlMsg.msg);
					myerl->zooKeeper->welcome(ERL_INT_VALUE(varType), ERL_INT_VALUE(varId), ERL_INT_VALUE(varX), ERL_INT_VALUE(varY), ERL_INT_VALUE(varSW), ERL_INT_VALUE(varMW), ERL_INT_VALUE(varW), ERL_INT_VALUE(varSpeed));
					erl_free_term(varType);
					erl_free_term(varId);
					erl_free_term(varX);
					erl_free_term(varY);
					erl_free_term(varSW);
					erl_free_term(varMW);
					erl_free_term(varW);
					erl_free_term(varSpeed);
				}
				break;

				case 4: // {4, Id, Val} -> feed being
				{
					ETERM *varId = erl_element(2, erlMsg.msg);
					ETERM *varVal = erl_element(3, erlMsg.msg);
					myerl->zooKeeper->feed(ERL_INT_VALUE(varId), ERL_INT_VALUE(varVal));
					erl_free_term(varId);
					erl_free_term(varVal);
				}
				break;

				case 5: // {5, X, Y} -> move being
				{
					ETERM *varId = erl_element(2, erlMsg.msg);
					ETERM *varX = erl_element(3, erlMsg.msg);
					ETERM *varY = erl_element(4, erlMsg.msg);
					myerl->zooKeeper->move(ERL_INT_VALUE(varId), ERL_INT_VALUE(varX), ERL_INT_VALUE(varY));
					erl_free_term(varId);
					erl_free_term(varX);
					erl_free_term(varY);
				}
				break;
			}
			erl_free_term(msgType);
		}
		erl_free_term(erlMsg.from);
		erl_free_term(erlMsg.msg);
	}
	return NULL;
}

int myerl_launch_listener(Myerl *myerl)
{
	myerl->alive = true;
	pthread_create(&(myerl->listener_thread), NULL, &myerl_listener, (void *) myerl);
	return 0;
}

int myerl_finalize(Myerl *myerl)
{
	myerl->alive = false;
	pthread_join(myerl->listener_thread, NULL);
	return 0;
}

void myerl_commander(Myerl *myerl, char* command_string)
{
	ETERM *command = erl_format(command_string); // eg. "{ok, 1234}"
	erl_reg_send(myerl->fd, "connector", command);
	erl_free_term(command);
}

